package com.example.studykotlin.kotlin_actual_combat.art.aidl.custom;

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.NonNull;

import com.example.studykotlin.kotlin_actual_combat.art.aidl.Book;
import com.example.studykotlin.kotlin_actual_combat.art.aidl.IOnNewBookArrivedListener;

import java.util.List;

/**
 * 手写binder
 */
public abstract class MyBookManagerImpl extends Binder implements IMyBookManager {

    private static final String TAG = "MyBookManagerImpl";

    public MyBookManagerImpl() {
        this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * 将 服务端的 IBinder 对象转换为 com.example.studykotlin.kotlin_actual_combat.art.aidl.IMyBookManager 接口
     * 区分进程，进程内返回服务端MyBookManagerImpl本身，进程外返回MyBookManagerImpl.proxy对象
     */
    public static IMyBookManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }

        //先查询这个binder在进程内有没有实现
        IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

        if (((iin != null) && (iin instanceof IMyBookManager))) {
            //如果有返回自身
            return ((IMyBookManager) iin);
        }
        //如果没有返回代理对象
        return new MyBookManagerImpl.Proxy(obj);
    }

    @Override
    public IBinder asBinder() {
        return this;
    }

    @Override
    protected boolean onTransact(int code, @NonNull Parcel data,Parcel reply, int flags) throws RemoteException {
        String test = DESCRIPTOR;
        switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_getBookList: {
                data.enforceInterface(test);//校验
                List<Book> bookList = this.getBookList();
                reply.writeNoException();//看方法注释可以简单理解为添加header部信息便于客户端验证，默认是0
                reply.writeTypedList(bookList);
                return true;
            }
            case TRANSACTION_addBook: {
                data.enforceInterface(DESCRIPTOR);
                Book book;
                if ((0 != data.readInt())) {
                    book = Book.CREATOR.createFromParcel(data);
                } else {
                    book = null;
                }
                //这里逻辑不够严谨,简单看
                this.addBook(book);
                reply.writeNoException();
                return true;
            }
            case TRANSACTION_registerListener: {
                data.enforceInterface(test);
                IOnNewBookArrivedListener listener;
                listener = IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());
                this.registerListener(listener);
                reply.writeNoException();
                return true;
            }
            case TRANSACTION_unregisterListener: {
                data.enforceInterface(test);
                IOnNewBookArrivedListener listener;
                listener = IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());
                this.unregisterListener(listener);
                reply.writeNoException();
                return true;
            }
            default: {
                return super.onTransact(code, data, reply, flags);
            }
        }

    }

    /**
     * 客户端
     */
    private static class Proxy implements IMyBookManager {
        private IBinder mRemote;
        List<Book> result;

        public Proxy(IBinder remote) {
            this.mRemote = remote;
        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();

            try {
                //存一个token用于在服务端做校验
                data.writeInterfaceToken(DESCRIPTOR);
                //这里还是在客户端，所以两个进程要通信就必须走transact过程
                //status代表执行的状态，这里可能为false(如果权限校验失败的情况下)
                boolean status = mRemote.transact(TRANSACTION_getBookList, data, reply, 0);
                reply.readException();//检查reply的header信息 =0正常，!=0则抛出异常
                result = reply.createTypedArrayList(Book.CREATOR);
            } catch (Exception e) {
                Log.e(TAG, "调用远程方法过程失败:getBookList");
                e.printStackTrace();
            } finally {
                //池里拿的用完得释放
                data.recycle();
                reply.recycle();
            }

            return result;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();

            try {
                data.writeInterfaceToken(DESCRIPTOR);
                if (book != null) {
                    data.writeInt(1);
                    book.writeToParcel(data,0);
                } else {
                    data.writeInt(0);
                }
                boolean status = mRemote.transact(TRANSACTION_addBook,data,reply,0);
                if (!status) {
                    //做添加图书失败处理
                }
                reply.readException();
            } catch (Exception e) {
                Log.e(TAG, "调用远程方法过程失败:addBook");
                e.printStackTrace();
            } finally {
                //池里拿的用完得释放
                data.recycle();
                data.recycle();
            }
        }

        @Override
        public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();

            try {
                data.writeInterfaceToken(DESCRIPTOR);
                data.writeStrongBinder(((listener != null) ? (listener.asBinder()) : (null)));
                boolean status = mRemote.transact(TRANSACTION_registerListener,data,reply,0);
                if (status) {
                    //做处理
                }
                reply.readException();
            } finally {
                data.recycle();
                reply.recycle();
            }
        }

        @Override
        public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();

            try {
                data.writeInterfaceToken(DESCRIPTOR);
                data.writeStrongBinder(((listener != null) ? (listener.asBinder()) : (null)));
                boolean status = mRemote.transact(TRANSACTION_unregisterListener,data,reply,0);
                if (status) {
                    //做处理
                }
                reply.readException();
            } finally {
                data.recycle();
                reply.recycle();
            }
        }

        @Override
        public IBinder asBinder() {
            return mRemote;
        }
    }
}
